<template>
  <div>
    <h1>像素图形生成工具</h1>
    <div
      style="margin: 10px 0; display: flex; justify-content: center; gap: 20px; align-items: center; flex-wrap: wrap;"
    >
      <div>
        <span>矩阵宽度: </span>
        <el-input
          v-model.number="width"
          type="number"
          min="1"
          max="100"
          style="width: 100px;"
        ></el-input>
      </div>
      <div>
        <span>矩阵高度: </span>
        <el-input
          v-model.number="height"
          type="number"
          min="1"
          max="100"
          style="width: 100px;"
        ></el-input>
      </div>
      <div>
        <span>选择颜色: </span>
        <el-color-picker
          v-model="selectedColor"
          :predefine="predefinedColors"
          format="hex"
        ></el-color-picker>
      </div>
      <div style="display: flex; align-items: center;">
        <span style="margin-right: 8px;">选择模式:</span>
        <el-select
          v-model="currentMode"
          placeholder="请选择"
          style="width: 140px;"
        >
          <el-option
            label="序号模式"
            value="id"
          ></el-option>
          <el-option
            label="位图模式"
            value="bitmap"
          ></el-option>
        </el-select>
      </div>
      <div>
        <span>图片名称: </span>
        <el-input
          v-model="imageName"
          style="width: 150px;"
          placeholder="输入图片名称"
        ></el-input>
      </div>
    </div>

    <!-- 像素网格容器 -->
    <div
      class="pixel-grid"
      @mousedown="startDrawing"
      @mouseup="stopDrawing"
      @mouseleave="stopDrawing"
    >
      <div
        v-for="(row, rowIndex) in grid"
        :key="rowIndex"
        class="pixel-row"
      >
        <div
          v-for="(pixel, colIndex) in row"
          :key="colIndex"
          class="pixel"
          :style="{ backgroundColor: pixel.color }"
          @mouseenter="handleCellEnter(rowIndex, colIndex)"
          @click="togglePixel(rowIndex, colIndex)"
        ></div>
      </div>

      <!-- 结果显示对话框 -->
      <el-dialog
        v-model="dialogVisible"
        :title="dialogTitle"
        width="35%"
        append-to-body
      >
        <pre
          style="white-space: pre-wrap; word-wrap: break-word; max-height: 400px; overflow: auto;">{{ dialogContent }}</pre>
        <template #footer>
          <el-button
            type="primary"
            @click="copyDialogContent"
          >复制内容</el-button>
          <el-button @click="dialogVisible = false">关闭</el-button>
        </template>
      </el-dialog>
    </div>

    <div style="text-align: center;">
      <div>
        <h3>说明：</h3>
        <p>1. 按住鼠标并移动到像素上以绘制图形。</p>
        <p>2. 模式选择：序号模式输出ID数组，位图模式输出字节数组。</p>
        <p>3. 导入图片生成时，请上传黑色或者透明色背景的图片！</p>
      </div>
      <div class="button-group">
        <el-button
          type="primary"
          size="default"
          class="generate-btn"
          @click="generateOutput"
        >生成</el-button>
        <el-upload
          action=""
          :auto-upload="false"
          :on-change="handleImageUpload"
          accept="image/*"
          :show-file-list="false"
        ><el-button
            type="success"
            size="default"
            class="generate-btn"
          >导入图片生成</el-button></el-upload>
        <el-button
          type="danger"
          size="default"
          class="generate-btn"
          @click="clearGrid"
        >清除</el-button>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ElMessage, ElColorPicker, ElSelect, ElOption, ElInput, ElDialog, ElButton } from 'element-plus'
import { ref, watch, computed } from 'vue'

// 自定义变量名
const imageName = ref('x')

// 网格尺寸响应式变量
const width = ref(8)
const height = ref(8)

// 对话框状态
const dialogVisible = ref(false)
const dialogTitle = ref('输出结果')
const dialogContent = ref('')

const copyDialogContent = async () => {
  try {
    await navigator.clipboard.writeText(dialogContent.value)
    ElMessage.success('内容复制成功')
  } catch (err) {
    ElMessage.error('复制失败，请手动复制')
  }
}

// 图片上传相关状态
const isProcessingImage = ref(false)

// 颜色和模式状态
// const selectedColor = ref('#3498db') // 默认蓝色
const selectedColor = ref('#ffffff')
const currentMode = ref('bitmap') // 默认序号模式

// 常用颜色（固定前三个）
const commonColors = ['#000000', '#FFFFFF', '#FF0000','#E8EAC3', '#EC6B81', '#4A7446'];
// 历史使用颜色（从localStorage读取）
const historyColors = ref([]);

// 组合预定义颜色：常用颜色 + 历史颜色（最多14个）
const predefinedColors = computed(() => {
  return [...commonColors, ...historyColors.value];
});

// 监听颜色选择变化，更新历史记录
watch(selectedColor, (newColor) => {
  if (!newColor || commonColors.includes(newColor)) return;

  // 如果颜色已在历史记录中，先移除
  const index = historyColors.value.indexOf(newColor);
  if (index !== -1) {
    historyColors.value.splice(index, 1);
  }

  // 添加到历史记录开头
  historyColors.value.unshift(newColor);

  // 限制历史记录最多10个
  if (historyColors.value.length > 10) {
    historyColors.value.pop();
  }
});

// const defaultGridColor='#f8f8f8'
const defaultGridColor = '#000000'

// 生成网格数据
const grid = ref<Array<Array<{ selected: boolean; id: number }>>>([])

// 初始化或更新网格
const updateGrid = () => {
  grid.value = Array.from({ length: height.value }, (_, rowIndex) =>
    Array.from({ length: width.value }, (_, colIndex) => ({
      selected: false,
      color: defaultGridColor, // 默认颜色
      // 计算S形编号：偶数行从左到右，奇数行从右到左
      id: colIndex % 2 === 0
        ? colIndex * height.value + rowIndex
        : colIndex * height.value + (height.value - 1 - rowIndex)
    }))
  )
}

// 初始化网格
updateGrid()

// 监听宽高变化，更新网格
watch([width, height], () => {
  updateGrid()
})
// 切换像素选中状态
const togglePixel = (rowIndex: number, colIndex: number) => {
  const pixel = grid.value[rowIndex][colIndex]
  pixel.color = pixel.color.toUpperCase() === selectedColor.value.toUpperCase() ?
    defaultGridColor.toUpperCase() : selectedColor.value.toUpperCase()
  pixel.selected = pixel.color.toUpperCase() !== defaultGridColor.toUpperCase()
}

// 处理图片上传
const handleImageUpload = async (file: any) => {
  if (!file.raw) return

  isProcessingImage.value = true
  // ElMessage.info('正在处理图片，请稍候...');

  try {
    // 创建图片对象
    const img = new Image()
    img.src = URL.createObjectURL(file.raw)

    await new Promise((resolve, reject) => {
      img.onload = resolve
      img.onerror = reject
    })

    // 创建canvas并绘制图片
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')!

    // 设置canvas尺寸为网格尺寸
    canvas.width = width.value
    canvas.height = height.value

    // 在canvas上绘制图片（会自动缩放）
    ctx.drawImage(img, 0, 0, width.value, height.value)

    // 获取像素数据
    const imageData = ctx.getImageData(0, 0, width.value, height.value)
    const pixels = imageData.data

    // 清空现有网格
    clearGrid()

    // 更新网格像素颜色
    for (let y = 0; y < height.value; y++) {
      for (let x = 0; x < width.value; x++) {
        const index = (y * width.value + x) * 4
        const r = pixels[index]
        const g = pixels[index + 1]
        const b = pixels[index + 2]
        const a = pixels[index + 3]

        // 应用对比度调整 (对比度值 >1 增加对比度，=1 正常，<1 降低对比度)
        const contrast = 3
        const factor = (259 * (contrast + 255)) / (255 * (259 - contrast))
        const adjustedR = Math.min(255, Math.max(0, Math.round(factor * (r - 128) + 128)))
        const adjustedG = Math.min(255, Math.max(0, Math.round(factor * (g - 128) + 128)))
        const adjustedB = Math.min(255, Math.max(0, Math.round(factor * (b - 128) + 128)))

        if (a < 128 ||
          (adjustedR < 20 && adjustedG < 20 && adjustedB < 20) ||
          (adjustedR > 230 && adjustedG > 230 && adjustedB > 230))
          continue

        // 颜色统一：将相似颜色合并 (值越小保留颜色越多，值越大对比度越高，建议范围32-128)
        // note：这里只能针对黑色或者透明背景的图片生效，否则会错乱
        const colorStep = 110
        const unifiedR = Math.round(adjustedR / colorStep) * colorStep
        const unifiedG = Math.round(adjustedG / colorStep) * colorStep
        const unifiedB = Math.round(adjustedB / colorStep) * colorStep

        // 跳过透明像素和接近黑色的背景像素 (RGB值均< 20 )
        // if (a < 128 || (unifiedR < 20 && unifiedG < 20  && unifiedB < 20 )) continue;

        // 转换为十六进制颜色
        const hexColor = `#${((1 << 24) + (unifiedR << 16) + (unifiedG << 8) + unifiedB).toString(16).slice(1).toUpperCase()}`

        // 更新网格像素
        grid.value[y][x].color = hexColor
        grid.value[y][x].selected = true
      }
    }

    ElMessage.success('图片已成功转换为像素图！')
  } catch (error) {
    ElMessage.error('图片处理失败，请重试')
    console.error('图片处理错误:', error)
  } finally {
    isProcessingImage.value = false
  }
}

// 生成输出结果
const generateOutput = () => {
  // 检查网格数据是否有效
  if (!grid.value || grid.value.length === 0) {
    ElMessage.warning('网格数据未初始化，请先设置有效的宽高值')
    return
  }
  const firstRow = grid.value[0]
  if (!firstRow || firstRow.length === 0) {
    ElMessage.warning('网格数据无效，无法生成输出')
    return
  }
  if (currentMode.value === 'id') {
    // 序号模式
    // 按颜色分组收集ID
    const colorGroups = new Map<string, number[]>()
    grid.value.forEach(row => {
      row.forEach(pixel => {
        if (pixel.selected) {
          if (!colorGroups.has(pixel.color.toUpperCase())) {
            colorGroups.set(pixel.color.toUpperCase(), [])
          }
          colorGroups.get(pixel.color.toUpperCase())!.push(pixel.id)
        }
      })
    })

    // 排序并格式化输出
    const formattedGroups = Array.from(colorGroups.entries()).map(([color, ids]) => {
      ids.sort((a, b) => a - b)
      return `{
    颜色: ${color.toUpperCase()}
    序号: [${ids.join(', ')}]
}`
    })

    const outputData = formattedGroups.join(',\n')
    console.log('按颜色分组的序号数据:\n', outputData)
    dialogTitle.value = '序号模式输出'
    dialogContent.value = `${outputData}`
    dialogVisible.value = true
  } else {
    // 位图模式 - 按颜色生成多个全量位图
    // 收集所有使用的颜色
    const colorSet = new Set<string>()
    grid.value.forEach(row => {
      row.forEach(pixel => {
        if (pixel.selected) {
          colorSet.add(pixel.color.toUpperCase())
        }
      })
    })
    const colors = Array.from(colorSet)

    // 为每种颜色生成位图数据
    const colorBitmaps = colors.map(color => {
      const bitmap: number[] = []
      // 遍历行(y轴)
      for (let y = 0; y < grid.value.length; y++) {
        const row = grid.value[y]
        if (!row) continue // 跳过空行
        let byte = 0
        // 遍历列(x轴)
        for (let x = 0; x < row.length; x++) {
          // 每8个像素组成一个字节
          if (x % 8 === 0 && x > 0) {
            bitmap.push(byte)
            byte = 0
          }
          // 检查当前像素是否为当前颜色
          const isCurrentColor = row[x]?.color.toUpperCase() === color.toUpperCase()
          console.log('isCurrentColor', row[x]?.color.toUpperCase(), color.toUpperCase())
          if (isCurrentColor) {
            // 设置对应位(从高位到低位)
            byte |= (1 << (7 - (x % 8)))
          }
        }
        // 添加当前行最后一个字节
        bitmap.push(byte)
      }

      // 格式化当前颜色的位图数据
      const hexBitmap = bitmap.map(b => `0x${b.toString(16).padStart(2, '0').toUpperCase()}`)
      const bytesPerLine = Math.ceil(width.value / 8)
      const formattedHex = []
      for (let i = 0; i < hexBitmap.length; i += bytesPerLine) {
        formattedHex.push(hexBitmap.slice(i, i + bytesPerLine).join(', '))
      }
      return {
        color,
        data: formattedHex.join(',\n        ')
      }
    })

    // 生成输出内容
    // 生成图层数据数组定义
    const layerArrays = colorBitmaps.map((item, index) => {
      const layerData = item.data
        .split('\n')
        .map(line => line.trim())
        .filter(line => line)
        .join('\n    ')
      return `const uint8_t img_${imageName.value}_layer_${index + 1}[] PROGMEM = {
    ${layerData}
};`
    }).join('\n\n')

    // 生成图层引用
    const layerReferences = colorBitmaps.map((item, index) => {
      return `{.color = ${item.color.replace('#', '0x')}, .data = img_${imageName.value}_layer_${index + 1}}`
    }).join(',\n    ')

    // 组合完整输出内容
    dialogContent.value = `${layerArrays}

const image_t img_${imageName.value} = {
  .width = ${width.value},
  .height = ${height.value},
  .layers_num = ${colorBitmaps.length},
  .layers = {
    ${layerReferences}
  }
};`

    console.log('多颜色位图数据 - 宽:', width.value, '高:', height.value)
    dialogTitle.value = '多颜色位图模式输出'
    dialogVisible.value = true
  }
}

// 在data中添加绘制状态变量
const isDrawing = ref(false)

// 在methods中添加鼠标事件处理方法
const startDrawing = () => {
  isDrawing.value = true
}

const stopDrawing = () => {
  isDrawing.value = false
}

const handleCellEnter = (rowIndex: number, colIndex: number) => {
  if (isDrawing.value) {
    grid.value[rowIndex][colIndex].color = selectedColor.value
    grid.value[rowIndex][colIndex].selected = true
  }
}

// 在methods中添加清除方法
const clearGrid = () => {
  grid.value.forEach(row => {
    row.forEach(pixel => {
      pixel.color = defaultGridColor
      pixel.selected = false
    })
  })
}
</script>

<style scoped>
.button-group {
  display: flex;
  gap: 10px;
  margin: 10px 0;
  align-items: center;
  flex-wrap: nowrap;
  width: 100%;
  justify-content: center;
}

.pixel-grid {
  margin: 80px 0;
}

.pixel-row {
  display: flex;
  justify-content: center;
}

.pixel {
  width: 30px;
  height: 30px;
  border: 1px solid #242424;
  margin: 0px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.generate-btn {
  margin-top: 20px;
  padding: 8px 16px;
  /* background-color: #2ecc71; */
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  width: 120px;
  height: 40px;
}

/* .generate-btn:hover {
  background-color: #27ae60;
} */

/* .grid-container {
  display: grid;
  grid-template-columns: repeat(32, 30px);
  grid-template-rows: repeat(8, 30px);
  gap: 2px;
}

.grid-cell {
  width: 32px;
  height: 32px;
  border: 1px solid #ddd;
  cursor: pointer;
} */

/* .clear-btn {
  margin-top: 20px;
  margin-left: 10px;
  padding: 8px 16px;
  background-color: #e74c3c;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
}

.clear-btn:hover {
  background-color: #c0392b;
} */
</style>
